package main

import (
	"context"
	"encoding/json"
	"errors"
	"gitee.com/kinwyb/appTools/common/socket"
	"gitee.com/kinwyb/appTools/manager"
	"runtime"
	"time"
)

var serverAddress string //服务器IP地址
var httpAddress string   //http服务地址

// 服务器tcp连接
var conn *socket.TcpClient

// 连接服务器
func initConnect(ctx context.Context) (err error) {
	conn, err = socket.NewTcpClient(ctx, &socket.TcpClientConfig{
		ServerAddress:     serverAddress,
		AutoReConnect:     true,
		ReConnectWaitTime: 5 * time.Second,
		Protocol:          socket.NewProtocol(nil),
		Log:               manager.ServiceLog,
		ErrorHandler: func(et socket.ErrorType, e error) {
			manager.ServiceLog.WithError(e).Errorf("tcp连接错误")
		},
		ConnectHandler: func() { //连接成功,发送一个消息通知服务端发送基础数据
			_ = conn.Write([]byte{0x9})
		},
		MessageHandler: tcpMsgHandler,
		CloseHandler: func() {
			manager.ServiceLog.Info("服务端链接断开")
		},
		ConnectTimeOut: 30 * time.Second,
	})
	if err == nil && conn != nil {
		conn.Connect()
	}
	return
}

// 发送消息
func sendMsg(msg *manager.Msg) {
	err := conn.Write(msg.Marshal())
	if err != nil {
		manager.ServiceLog.WithError(err).Error("消息发送失败")
	}
}

// 消息处理
func tcpMsgHandler(msg []byte) {
	if len(msg) < 1 {
		manager.ServiceLog.WithField("info", msg).Error("收到服务端消息异常")
		return
	}
	td := manager.GetMsg()
	err := td.UnMarshal(msg)
	if err != nil {
		manager.ServiceLog.WithError(err).Error("收到服务器数据解析异常")
		td.Clean()
		return
	}
	switch td.Cmd {
	case manager.CommandServerHttpAddress: //服务端http地址
		manager.ServiceLog.Info("收到到服务端http地址")
		info := manager.CmdServerHttpAddress{}
		_ = info.UnMarshal(td.Data)
		if info.Status != 'Y' {
			manager.ServiceLog.WithField("info", info).Info("服务端http内容异常")
			td.Data = []byte{'N'}
		} else {
			httpAddress = info.Address
			td.Data = []byte{'Y'}
		}
		sendMsg(td)
	case manager.CommandStopProcess: //停止进程
		manager.ServiceLog.Info("停止程序")
		var e error
		if runProcess == nil {
			e = errors.New("runProcess is nil")
		} else {
			td.Data = []byte{'Y'}
			e = runProcess.Stop()
		}
		if e != nil {
			td.Data = []byte{'N'}
			td.Data = append(td.Data, []byte(e.Error())...)
		}
		sendMsg(td)
	case manager.CommandStartProcess: //启动进程
		manager.ServiceLog.Info("启动程序")
		var e error
		if runProcess == nil {
			e = errors.New("runProcess is nil")
		} else {
			e = runProcess.Start()
			td.Data = []byte{'Y'}
		}
		if e != nil {
			td.Data = []byte{'N'}
			td.Data = append(td.Data, []byte(e.Error())...)
		}
		sendMsg(td)
	case manager.CommandStateProcess: //进程状态
		//manager.ServiceLog.Info("获取进程状态")
		state := manager.CmdProcessState{
			Tag: tag,
			//ID:        runProcess.ID,
			Os:  runtime.GOOS + "_" + runtime.GOARCH,
			App: appName,
			//Version:   runProcess.version(),
			//IsStart:   runProcess.IsStart,
			//StartTime: runProcess.startTime,
		}
		if runProcess != nil {
			state.ID = runProcess.ID
			state.Version = runProcess.version()
			state.IsStart = runProcess.IsStart
			state.StartTime = runProcess.startTime
			if runProcess.IsStart {
				state.Mem, state.Cpu = runProcess.ProcessUseMemAndCpu()
			}
		}
		td.Data = state.Marshal()
		sendMsg(td)
	case manager.CommandUpdateProcessExec: //更新运行程序
		manager.ServiceLog.Info("更新运行程序")
		info := manager.CmdServerExecVersion{}
		_ = info.UnMarshal(td.Data)
		if info.Status != 'Y' {
			manager.ServiceLog.WithField("info", info).Info("服务端版本内容异常")
			td.Data = []byte{'N'}
		} else {
			td.Data = []byte{'Y'}
			serverVersion = info.Version
			e := doUpdateProcessExec()
			if e != nil {
				td.Data[0] = 'N'
				td.Data = append(td.Data, []byte(e.Error())...)
			}
		}
		sendMsg(td)
	case manager.CommandServerExecVersion: //服务端软件版本
		//manager.ServiceLog.Info("收到服务端软件版本")
		info := manager.CmdServerExecVersion{}
		_ = info.UnMarshal(td.Data)
		if info.Status != 'Y' {
			manager.ServiceLog.WithField("info", info).Info("服务端版本内容异常")
			td.Data = []byte{'N'}
		} else {
			serverVersion = info.Version
			td.Data = []byte{'Y'}
		}
		sendMsg(td)
	case manager.CommandHttpRequest: //http请求
		req := manager.CmdHttpRequest{}
		_ = json.Unmarshal(td.Data, &req)
		if req.Url == "" {
			td.Data = []byte("http请求地址空")
		}
		data, err := httpRequest(req)
		if err != nil {
			td.Data = []byte(err.Error())
		} else {
			td.Data = data
		}
		sendMsg(td)
	}
	td.Clean()
}
